package com.rockzhai.ai;

import java.util.*;  
import java.awt.*;  
import java.awt.event.*;
import java.io.FileInputStream;

import javax.swing.*;
import sun.audio.*;

//本人Gitee主页：https://gitee.com/mimocvb
public class Ai implements MouseMotionListener{  

    private static DrawingPanel panel=new DrawingPanel(720,720); 
    private static Graphics g=panel.getGraphics();  
    public static boolean isBlack=true;//标志棋子的颜色  
    public static int[][] chessBoard=new int[17][17]; //棋盘棋子的摆放情况：0无子，1黑子，－1白子  
    private static HashSet<Point> toJudge=new HashSet<Point>(); // ai可能会下棋的点  
    private static int dr[]=new int[]{-1,1,-1,1,0,0,-1,1}; // 方向向量  
    private static int dc[]=new int[]{1,-1,-1,1,-1,1,0,0}; //方向向量  
    public static final int MAXN=1<<28;  
    public static final int MINN=-MAXN;    
    private static int searchDeep=4;    //搜索深度  
    private static final int size=15;   //棋盘大小  
    public static boolean isFinished=false;  
    private static int oldx,oldy;
	static String xianchengsu;
	public static int a;
	static int chess_style = 2;
	
    private static Image image2_1 = (Image) new ImageIcon("file/A_black.png").getImage();
    private static Image image2_2 = (Image) new ImageIcon("file/A_withe.png").getImage();
    private static Image image3_1 = (Image) new ImageIcon("file/B_black.png").getImage();
    private static Image image3_2 = (Image) new ImageIcon("file/B_withe.png").getImage();
    private static Image image4_1 = (Image) new ImageIcon("file/C_black.png").getImage();
    private static Image image4_2 = (Image) new ImageIcon("file/C_withe.png").getImage();
    
    public static void main(String[] args){  
        MyMouseEvent myMouseEvent=new MyMouseEvent();
        panel.addMouseListener(myMouseEvent);
        panel.addMouseMotionListener(myMouseEvent);
        initChessBoard();
    }  
    
    // 初始化函数，绘图  
    public static void initChessBoard(){  
    	
        isBlack=false;  
        toJudge.clear();  
        panel.clear();   
        g.setColor(Color.BLACK); 
        
        for(int i=50;i<=680;i+=45){  
            g.drawLine(50,i,680,i);  
            g.drawLine(i,50,i,680);  
        }  
        
        // 初始化棋盘  
        for(int i=1;i<=15;++i)  
            for(int j=1;j<=15;++j)  
                chessBoard[i][j]=0;  
        
        //ai先手  绘制棋子; 
        switch(chess_style){
        case 1:g.drawImage(image2_1, 348, 348, DrawingPanel.g3);break;
        case 2:g.drawImage(image3_1, 348, 348, DrawingPanel.g3);break;
        case 3:g.drawImage(image4_1, 348, 348, DrawingPanel.g3);break;
        }
        
        //画当前所下的棋子的标记
    	g.setColor(Color.RED);
    	g.fillOval(363,363 , 5, 5);
    	
    	//记录上一步棋的绘制坐标
        oldx=348;
        oldy=348;
        
        chessBoard[8][8]=1;  
        for(int i=0;i<8;++i)  
            if(1<=8+dc[i] && 8+dc[i]<=size && 1<=8+dr[i] && 8+dr[i]<=size){  
               Point now=new Point(8+dc[i],8+dr[i]);  
                if(!toJudge.contains(now))  
                    toJudge.add(now);  
            }  
        isBlack=false; 
     
    }  
    

    
	// 通过点击事件，得到棋子位置进行下棋  
    @SuppressWarnings("restriction")
	public static void putChess(int x,int y,int z){  
    	
    	if(z==1){
    		
    		DrawingPanel.AIus("    AI状态：正在计算中");
    		
    	}
    	else if(z == 0){
    		
    		DrawingPanel.AIus("    AI状态：无");
    		
    	}

    	switch(chess_style){
    	case 1:
        	//清除上次标记
        	if(oldx != 0){
        		if(isBlack)
        			g.drawImage(image2_2, oldx, oldy, DrawingPanel.g3);
                else   
                	g.drawImage(image2_1, oldx, oldy, DrawingPanel.g3);
        	}
        	//画棋子
            if(isBlack)
            	g.drawImage(image2_1, x-17+6, y-17+6, DrawingPanel.g3);
            else   
            	g.drawImage(image2_2, x-17+6, y-17+6, DrawingPanel.g3);
            break;
    	case 2:
        	//清除上次标记
        	if(oldx != 0){
        		if(isBlack)
        			g.drawImage(image3_2, oldx, oldy, DrawingPanel.g3);
                else   
                	g.drawImage(image3_1, oldx, oldy, DrawingPanel.g3);
        	}
        	//画棋子
            if(isBlack)
            	g.drawImage(image3_1, x-17+6, y-17+6, DrawingPanel.g3);
            else   
            	g.drawImage(image3_2, x-17+6, y-17+6, DrawingPanel.g3);
            break;
    	case 3:
        	//清除上次标记
        	if(oldx != 0){
        		if(isBlack)
        			g.drawImage(image4_2, oldx, oldy, DrawingPanel.g3);
                else   
                	g.drawImage(image4_1, oldx, oldy, DrawingPanel.g3);
        	}
        	//画棋子
            if(isBlack)
            	g.drawImage(image4_1, x-17+6, y-17+6, DrawingPanel.g3);
            else   
            	g.drawImage(image4_2, x-17+6, y-17+6, DrawingPanel.g3);
            break;
    	
    	}
    	
        //画点标记
    	g.setColor(Color.RED);
    	g.fillOval(x-1+5,y-1+5, 5, 5);
    	
    	//记录上一步棋的绘制坐标
        oldx=x-17+6;
        oldy=y-17+6;
        
    	//下棋音效
    	try {
    		FileInputStream fis = new FileInputStream("file/chessmusic.wav");
    		AudioStream as=new AudioStream(fis);
    		AudioPlayer.player.start(as);
    	} catch (Exception e) {
    		// TODO Auto-generated catch block
    		e.printStackTrace();
    	}
    	
        chessBoard[y/45][x/45]=isBlack?1:-1;  
        if(isEnd(x/45,y/45)){  
            String s=Ai.isBlack?"黑子胜":"白子胜";  
            JOptionPane.showMessageDialog(null,s);  
            isBlack=true;  
            initChessBoard();
        }  
        else{  
            Point p=new Point(x/45,y/45);  
            if(toJudge.contains(p))  
                toJudge.remove(p); 
            for(int i=0;i<8;++i){  
                Point now=new Point(p.x+dc[i],p.y+dr[i]);  
                if(1<=now.x && now.x<=size && 1<=now.y && now.y<=size && chessBoard[now.y][now.x]==0)  
                    toJudge.add(now);  
            }  
        } 
    	

    }  
    
    public void style(){
    	
		switch(chess_style){
		case 1:chess_style = 2;break;
		case 2:chess_style = 3;break;
		case 3:chess_style = 1;break;
		}
		
	}

    // ai博弈入口函数  
    public static void myAI(){  
    	
        Node node=new Node();  
        dfs(0,node,MINN,MAXN,null); 
        Point now=node.bestChild.p;  
        toJudge.remove(now);  
        putChess(now.x*45,now.y*45,0); 
        isBlack=false;  
    }  
  
    // AI
    private static void dfs(int deep,Node root,int alpha,int beta,Point p){  
    	
        if(deep==searchDeep){  
            root.mark=getMark(); 
            return;  
        }  
        
        
        ArrayList<Point> judgeSet=new ArrayList<Point>();  
        Iterator<Point> it=toJudge.iterator();  
        while(it.hasNext()){  
            Point now=new Point((Point)it.next());  
            judgeSet.add(now);  
        }  
        it=judgeSet.iterator();  
        while(it.hasNext()){  
            Point now=new Point((Point)it.next());  
            Node node=new Node();  
            node.setPoint(now);  
            root.addChild(node);  
            boolean flag=toJudge.contains(now);  
            chessBoard[now.y][now.x]=((deep&1)==1)?-1:1;  
            if(isEnd(now.x,now.y)){  
                root.bestChild=node;  
                root.mark=MAXN*chessBoard[now.y][now.x];  
                chessBoard[now.y][now.x]=0;  
                return;  
            }  
  
            boolean flags[]=new boolean[8]; //标记回溯时要不要删掉  
            Arrays.fill(flags,true);  
            for(int i=0;i<8;++i){  
                Point next=new Point(now.x+dc[i],now.y+dr[i]);  
                if(1<=now.x+dc[i] && now.x+dc[i]<=size && 1<=now.y+dr[i] && now.y+dr[i]<=size && chessBoard[next.y][next.x]==0){  
                    if(!toJudge.contains(next)){  
                        toJudge.add(next);  
                    }  
                    else flags[i]=false;  
                }  
            }  
              
            if(flag)   
                toJudge.remove(now);  
            dfs(deep+1,root.getLastChild(),alpha,beta,now);  
            chessBoard[now.y][now.x]=0;  
            if(flag)  
                toJudge.add(now);  
            for(int i=0;i<8;++i)  
                if(flags[i])  
                    toJudge.remove(new Point(now.x+dc[i],now.y+dr[i]));  
            
            // alpha beta剪枝  
            // min层  
            if((deep&1)==1){  
                if(root.bestChild==null || root.getLastChild().mark<root.bestChild.mark){  
                    root.bestChild=root.getLastChild();  
                    root.mark=root.bestChild.mark;  
                    if(root.mark<=MINN)  
                        root.mark+=deep;  
                    beta=Math.min(root.mark,beta);  
                }  
                if(root.mark<=alpha)  
                    return;  
            }  
            
            // max层  
            else{  
                if(root.bestChild==null || root.getLastChild().mark>root.bestChild.mark){  
                    root.bestChild=root.getLastChild();  
                    root.mark=root.bestChild.mark;  
                    if(root.mark==MAXN)  
                        root.mark-=deep;  
                    alpha=Math.max(root.mark,alpha);  
                }  
                if(root.mark>=beta)  
                    return;  
            }  
        }  
        
    }  
  
    public static int getMark(){  
        int res=0;  
        for(int i=1;i<=size;++i){  
            for(int j=1;j<=size;++j){  
                if(chessBoard[i][j]!=0){  
                    // 行  
                    boolean flag1=false,flag2=false;  
                    int x=j,y=i;  
                    int cnt=1;  
                    int col=x,row=y;  
                    while(--col>0 && chessBoard[row][col]==chessBoard[y][x]) ++cnt;  
                    if(col>0 && chessBoard[row][col]==0) flag1=true;  
                    col=x;row=y;  
                    while(++col<=size && chessBoard[row][col]==chessBoard[y][x]) ++cnt;  
                    if(col<=size && chessBoard[row][col]==0) flag2=true;  
                    if(flag1 && flag2)  
                        res+=chessBoard[i][j]*cnt*cnt;  
                    else if(flag1 || flag2) res+=chessBoard[i][j]*cnt*cnt/4;   
                    if(cnt>=5) res=MAXN*chessBoard[i][j];  
                    // 列  
                    col=x;row=y;  
                    cnt=1;flag1=false;flag2=false;  
                    while(--row>0 && chessBoard[row][col]==chessBoard[y][x]) ++cnt;  
                    if(row>0 && chessBoard[row][col]==0) flag1=true;  
                    col=x;row=y;  
                    while(++row<=size && chessBoard[row][col]==chessBoard[y][x]) ++cnt;  
                    if(row<=size && chessBoard[row][col]==0) flag2=true;  
                    if(flag1 && flag2)  
                        res+=chessBoard[i][j]*cnt*cnt;  
                    else if(flag1 || flag2)  
                        res+=chessBoard[i][j]*cnt*cnt/4;  
                    if(cnt>=5) res=MAXN*chessBoard[i][j];  
                    // 左对角线  
                    col=x;row=y;  
                    cnt=1;flag1=false;flag2=false;  
                    while(--col>0 && --row>0 && chessBoard[row][col]==chessBoard[y][x]) ++cnt;  
                    if(col>0 && row>0 && chessBoard[row][col]==0) flag1=true;  
                    col=x;row=y;  
                    while(++col<=size && ++row<=size && chessBoard[row][col]==chessBoard[y][x]) ++cnt;  
                    if(col<=size && row<=size && chessBoard[row][col]==0) flag2=true;  
                    if(flag1 && flag2)    
                        res+=chessBoard[i][j]*cnt*cnt;  
                    else if(flag1 || flag2) res+=chessBoard[i][j]*cnt*cnt/4;  
                    if(cnt>=5) res=MAXN*chessBoard[i][j];  
                    // 右对角线  
                    col=x;row=y;  
                    cnt=1;flag1=false;flag2=false;  
                    while(++row<=size && --col>0 && chessBoard[row][col]==chessBoard[y][x]) ++cnt;  
                    if(row<=size && col>0 && chessBoard[row][col]==0) flag1=true;  
                    col=x;row=y;  
                    while(--row>0 && ++col<=size && chessBoard[row][col]==chessBoard[y][x]) ++cnt;  
                    if(row>0 && col<=size && chessBoard[i][j]==0) flag2=true;  
                    if(flag1 && flag2)  
                        res+=chessBoard[i][j]*cnt*cnt;  
                    else if(flag1 || flag2) res+=chessBoard[i][j]*cnt*cnt/4;  
                    if(cnt>=5) res=MAXN*chessBoard[i][j];  
                      
                }  
            }  
        }  
        return res;  
    }  
  
    // for debug  
    public static void debug(){  
        for(int i=1;i<=size;++i){  
            for(int j=1;j<=size;++j){  
                System.out.printf("%d\t",chessBoard[i][j]);  
            }  
            System.out.println("");  
        }  
    }  
  
    // 判断是否一方取胜  
    public static boolean isEnd(int x,int y){  
    	
        // 判断一行是否五子连珠  
        int cnt=1;  
        int col=x,row=y;  
        while(--col>0 && chessBoard[row][col]==chessBoard[y][x]) ++cnt;  
        col=x;row=y;  
        while(++col<=size && chessBoard[row][col]==chessBoard[y][x]) ++cnt;  
        if(cnt>=5){  
            isFinished=true;  
            return true;  
        }  
        
        // 判断一列是否五子连珠  
        col=x;row=y;  
        cnt=1;  
        while(--row>0 && chessBoard[row][col]==chessBoard[y][x]) ++cnt;  
        col=x;row=y;  
        while(++row<=size && chessBoard[row][col]==chessBoard[y][x]) ++cnt;  
        if(cnt>=5){  
            isFinished=true;  
            return true;  
        }  
        
        // 判断左对角线是否五子连珠  
        col=x;row=y;  
        cnt=1;  
        while(--col>0 && --row>0 && chessBoard[row][col]==chessBoard[y][x]) ++cnt;  
        col=x;row=y;  
        while(++col<=size && ++row<=size && chessBoard[row][col]==chessBoard[y][x]) ++cnt;  
        if(cnt>=5){  
            isFinished=true;  
            return true;  
        }  
        
        // 判断右对角线是否五子连珠  
        col=x;row=y;  
        cnt=1;  
        while(++row<=size && --col>0 && chessBoard[row][col]==chessBoard[y][x]) ++cnt;  
        col=x;row=y;  
        while(--row>0 && ++col<=size && chessBoard[row][col]==chessBoard[y][x]) ++cnt;  
        if(cnt>=5){  
            isFinished=true;  
            return true;  
        }  
        return false;  
    }

	@Override
	public void mouseDragged(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
	}


	
	@Override
	public void mouseMoved(MouseEvent arg0) {
		// TODO Auto-generated method stub
	
	}

}  
  
// 二叉树节点  
class Node{  
    public Node bestChild=null;  
    public ArrayList<Node> child=new ArrayList<Node>();  
    public Point p=new Point();  
    public int mark;  
    Node(){  
        this.child.clear();  
        bestChild=null;  
        mark=0;  
    }  
    public void setPoint(Point r){  
        p.x=r.x;  
        p.y=r.y;  
    }  
    public void addChild(Node r){  
        this.child.add(r);  
    }  
    public Node getLastChild(){  
        return child.get(child.size()-1);  
    }  
}  

// 实现鼠标事件的接口  
class MyMouseEvent implements MouseListener{  
	
	static int x;
	static int y;
	
	public void mouseClicked(MouseEvent e){  //鼠标按键在组件上单击（按下并释放）时调用。
    	
    	x=round(e.getX());
    	y=round(e.getY());
    	
    	MyThread myThread = new MyThread();
        
        myThread.start();

    }  
	
    public void mouseEntered(MouseEvent e){		//鼠标进入到组件上时调用。
    	
    }  
     
    public static int round(int x){            // 得到鼠标点击点附近的棋盘精准点 
        return (x%45<22)?x/45*45:x/45*45+45;  
    }  
    
    public void mouseExited(MouseEvent e){		 //鼠标离开组件时调用。
    	
    }  
    public void mouseReleased(MouseEvent e){	//鼠标按钮在组件上释放时调用。
    	
    }  
    public void mousePressed(MouseEvent e){		//鼠标按键在组件上按下时调用。  
    	
    }  
}

//启动AI运算线程
class MyThread extends Thread {
	
	@Override
	@SuppressWarnings("deprecation")
    public void run(){
        //super.run();
        
        if(MyMouseEvent.x>=45 && MyMouseEvent.x<=675 && MyMouseEvent.y>=45 && MyMouseEvent.y<=675 && Ai.chessBoard[MyMouseEvent.y/45][MyMouseEvent.x/45]==0 && Ai.isBlack==false){  
           Ai.putChess(MyMouseEvent.x,MyMouseEvent.y,1);  
                	
           if(!Ai.isFinished){   //判断是否为AI走棋
                    	
        	   Ai.isBlack=true;  //设置当前为AI下棋
        	   Ai.myAI();        //调用AI开始执行
                        
           }  
           Ai.isFinished=false;  //设置AI下棋完毕
                    
        }
        stop();
        interrupt();
    }
}
    


